﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf;

namespace 数字孪生Demo.Model3D
{
    // 筒仓
    public class SiloModel3D : VisualObject3D
    {
        GeometryModel3D Body = new GeometryModel3D();
        GeometryModel3D Railings = new GeometryModel3D();
        GeometryModel3D Stairs = new GeometryModel3D();

        public SiloModel3D()
        {
            Body.Material = MaterialHelper.CreateMaterial(Colors.LightGray, 0.5);
            Railings.Material = MaterialHelper.CreateMaterial(Colors.Orange, 0.5);
            Stairs.Material = MaterialHelper.CreateMaterial(Colors.Brown, 0.5);

            InitModel();

            Model3DGroup group = new Model3DGroup();
            group.Children.Add(Body);
            group.Children.Add(Railings);
            group.Children.Add(Stairs);
            this.Visual3DModel = group;
        }

        #region 依赖属性
        // 高度
        public double Height
        {
            get { return (double)GetValue(HeightProperty); }
            set { SetValue(HeightProperty, value); }
        }
        public static readonly DependencyProperty HeightProperty =
            DependencyProperty.Register("Height",
                typeof(double), typeof(SiloModel3D),
                new PropertyMetadata(20.0, OnPropertyChanged));

        // 直径
        public double Diameter
        {
            get { return (double)GetValue(DiameterProperty); }
            set { SetValue(DiameterProperty, value); }
        }
        public static readonly DependencyProperty DiameterProperty =
            DependencyProperty.Register("Diameter", typeof(double), typeof(SiloModel3D),
                new PropertyMetadata(40.0, OnPropertyChanged));

        // 圆顶高度
        public double DomeHeight
        {
            get { return (double)GetValue(DomeHeightProperty); }
            set { SetValue(DomeHeightProperty, value); }
        }
        public static readonly DependencyProperty DomeHeightProperty =
            DependencyProperty.Register("DomeHeight", typeof(double), typeof(SiloModel3D),
                new PropertyMetadata(8.0, OnPropertyChanged));

        // 圆顶直径
        public double DomeDiameter
        {
            get { return (double)GetValue(DomeDiameterProperty); }
            set { SetValue(DomeDiameterProperty, value); }
        }
        public static readonly DependencyProperty DomeDiameterProperty =
            DependencyProperty.Register("DomeDiameter", typeof(double), typeof(SiloModel3D),
                new PropertyMetadata(38.0, OnPropertyChanged));

        #endregion

        #region 依赖方法
        private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as SiloModel3D)?.InitModel();
        }
        #endregion


        private void InitModel()
        {
            // Body
            var bodyBuilder = new MeshBuilder(false, false);

            var p0 = new Point(0, 0);
            var p1 = new Point(Diameter / 2, 0);
            var p2 = new Point(Diameter / 2, Height);
            var p3 = new Point(DomeDiameter / 2, Height);

            var section = new List<Point> { p0, p1, p1, p2, p2, p3 };
            var indices = new List<int> { 0, 1, 2, 3, 4, 5 };
            int n = 40;
            for (int i = n; i >= 0; i--)    // 包括顶点在内实际是41个点
            {
                double f1 = (double)i / n;
                section.Add(section.Last());
                section.Add(new Point(DomeDiameter / 2 * f1, Height + DomeHeight * (1 - f1 * f1)));
            }
            indices.AddRange(Enumerable.Range(6,2 * (n + 1)).ToList());

            bodyBuilder.AddSurfaceOfRevolution(new Point3D(0, 0, 0), new Vector3D(0, 0, 1), section, indices, 80);
            Body.Geometry = bodyBuilder.ToMesh(true);

            // Stairs 楼梯
            MeshBuilder stairBuilder = new MeshBuilder(false, false);
            double stairLength = 1.0;
            double stairWidth = 0.3;
            double stairHeight = 0.05;
            double riseHeight = 0.15;     // 上升高度
            int steps = (int)(Height / riseHeight);

            double r = Diameter / 2 + stairLength * 0.5;
            double rr = Diameter / 2 + stairLength * 0.95;
            var baseRailings = new List<Point3D>();

            double stepLength = 0.3;  // 每一步弧长
            double baseRad = stepLength / r;   // 基准弧度
            for (int i = 0; i < steps; i++)
            {
                double theta = baseRad * i;
                var p = new Point3D(r * Math.Cos(theta),r * Math.Sin(theta),i * riseHeight + stairHeight / 2);
                var x = new Vector3D(Math.Cos(theta),Math.Sin(theta),0);
                var z = new Vector3D(0,0,1);
                var y = Vector3D.CrossProduct(x, z);
                stairBuilder.AddBox(p,x,y,stairLength,stairWidth,stairHeight);
                baseRailings.Add(new Point3D(rr * Math.Cos(theta), rr * Math.Sin(theta),i * riseHeight + stairHeight));
            }
            Stairs.Geometry = stairBuilder.ToMesh(true);

            //Railings 栅栏
            MeshBuilder railingBuilder = new MeshBuilder(false, false);

            double lastRad = (steps * baseRad);
            double railingHeight = 0.8;
            double railingDiameter = 0.05;
            double railingDistance = 0.5;
            int topCount = (int)(Diameter * Math.PI / railingDistance);
            double topRadius = Diameter / 2 - railingDiameter;
            for (int i = 0; i < topCount; i++)
            {
                double theta = lastRad + (2 * Math.PI * i / topCount);
                baseRailings.Add(new Point3D(topRadius * Math.Cos(theta), topRadius * Math.Sin(theta), Height));
            }
            foreach (var point in baseRailings)
            {
                railingBuilder.AddCylinder(point, point + new Vector3D(0,0,railingHeight),railingDiameter,10);
            }

            // Top railing
            int tubeCount = 3;
            for (int i = 1; i <= tubeCount; i++)
            {
                double h = railingHeight * i / tubeCount;
                Point3D[] path = baseRailings.Select(b => b + new Vector3D(0, 0, h)).ToArray();
                railingBuilder.AddTube(path, railingDiameter, 20, false);
            }

            Railings.Geometry = railingBuilder.ToMesh(true);
        }

        public override void OnSelected(bool isSelected)
        {
            double opacity = isSelected ? 1.0 : 0.5;
            Body.Material = MaterialHelper.CreateMaterial(Colors.LightGray, opacity);
            Railings.Material = MaterialHelper.CreateMaterial(Colors.Orange, opacity);
            Stairs.Material = MaterialHelper.CreateMaterial(Colors.Brown, opacity);
        }
    }
}
